package org.example.myframework.frame.common.redis.utils;

import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
public class RedisUtil {

    @Resource
    private RedisTemplate<String, Object> luaTemplate;

    private static RedisTemplate<String, Object> redisTemplate;

    @Resource
    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        RedisUtil.redisTemplate = redisTemplate;
    }


    /**
     * 校验cas操作是否成功
     */
    private DefaultRedisScript<Boolean> casScript;

    /**
     * 在项目启动之后就动态加载lua脚本
     */
    @PostConstruct
    public void init() {
        casScript = new DefaultRedisScript<>();
        // lua脚本的类型
        casScript.setResultType(Boolean.class);
        // lua脚本的加载地址
        casScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("compareAndSet.lua")));
    }

    /**
     * 通过lua脚本实现set操作
     * @param key
     * @param oldValue
     * @param newValue
     * @return
     */
    public Boolean compareAndSet(String key, Long oldValue, Long newValue) {
        List<String> keys = new ArrayList<>();
        keys.add(key);
        return (Boolean) luaTemplate.execute(casScript, keys, oldValue, newValue);
    }
    /**
     * 新增方法
     * @param key
     * @param value
     */
    public static void set(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 检查redis中是否存在key
     *
     * @param key 键
     */
    public static Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 获取redis中key的值
     * @param key
     * @return
     */
    public static Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 删除redis中key的值
     * @param key
     */
    public static Boolean delete(String key) {
        return redisTemplate.delete(key);
    }

    /**
     * 设置redis中key的值，如果key不存在，则设置，用于加锁
     * @param key
     * @param value
     * @param time
     * @param TimeUnit
     * @return
     */
    public static Boolean setNx(String key, String value, Long time, TimeUnit TimeUnit) {
        return redisTemplate.opsForValue().setIfAbsent(key, value, time, TimeUnit);
    }
}
